﻿#pragma once
#include "Support/rapidjson/error/en.h"

#define CHECK_RE_FALSE(P) if(nullptr == P) { CommonFunc::ErrorMessageBox(CString("null pointer!")); return false; }
#define CHECK_RETURN(P) if(nullptr == P) { CommonFunc::ErrorMessageBox(CString("null pointer!")); return; }
#define CHECK_CONTINUE(P) if(nullptr == P) { CommonFunc::ErrorMessageBox(CString("null pointer!")); continue; }
#define CHECK_RE_EPOINTER(P) if (nullptr == P) { return E_POINTER; }

class CommonFunc
{
public:
	static void ErrorMessageBox(LPCWSTR errorMessage);

	static void CheckFxWarning(LPD3DXBUFFER pCode);		// 检测FX文件是否有警告 并防止泄漏

	static bool Write8BitBmp(const std::wstring &wpath, const BYTE* pBmpBuf, RGBQUAD* pColorTable, int imWidth, int imHeight);

	static bool Read8BitBmpWithBYTE(const std::wstring &wpath, BYTE* &pBmpBuf, int* imWidth, int* imHeight);

	//static bool Read8BitBmpWithColor(const std::wstring &wpath, _StructRGB** &pRGBBuf, int* imWidth, int* imHeight);

	static bool Read24BitBmp(const std::wstring &wpath, _stRGB* &pRGBBuf, int* imWidth, int* imHeight);

	static std::wstring ReadInputFile(const std::wstring &path);

	static void RelativePath2FullPath(const std::wstring &wpath, std::wstring &wpathOut);

	static std::wstring StringToWString(const std::string &strIn);

	static std::string WStringToString(const std::wstring &wstrIn);

	// 大小写转化用transform(string.begin(), string.end(), string.begin(), ::toupper) or ::tolower

	static void GetScreenWidthnHeight(int* nWidth, int* nHeight);	// 获取窗口分辨率

	static void GetMyPersonalLocation(std::wstring& wstrOut);	// 获取我的文档的位置

	static RGBQUAD* Get8BitColorTable();

	static void GetPersonalPathCacheDirectory(std::wstring &wPathOut);	// 创建cache隐藏文件夹

	static D3DXVECTOR2 Cursor2CameraSpace(const CPoint& ptCursor);		// 鼠标的窗口坐标转换到摄像机空间

	// 取得FolderPath(FolderPath以\\结尾)路径下.DocumentFormat格式的所有符合的文件名 不包括下级目录
	static void GetFolderFile(const std::wstring& FolderPath, const std::wstring& DocumentFormat, std::list<std::wstring>& FileNameList);

	template <typename T>
	static bool IsTwoSetHaveSameElement(const std::set<T>& setA, const std::set<T>& setB)
	{
		if (setA.empty() || setB.empty())
		{
			return false;
		}
		std::set<T> temp_set = setA;
		for (const auto& itSet : setB)
		{
			auto insertResult = temp_set.insert(itSet);
			if (!insertResult.second)
			{
				// 插入失败 说明重复
				return true;
			}
		}
		return false;
	}

	template <typename T>
	static void SetUIOrientation(T* pUI, const std::wstring& strIn)		// 通过Orientation属性设置控件位置
	{
		if (strIn.empty())
		{
			return;
		}
		CHECK_RETURN(pUI);
		int x = 0, y = 0;
		int screenWidth, screenHeight;
		GetScreenWidthnHeight(&screenWidth, &screenHeight);
		
		// UPPER_LEFT 默认就行
		if (L"LOWER_LEFT" == strIn)
		{
			y = screenHeight - pUI->GetHeight();
		}
		pUI->SetLocation(x, y);
	}

	template <typename _TOutputHandle, typename CONT>
	static bool ReadJsonFolder(const std::wstring& wFilePath, CONT* cont)		// 读该文件夹下的Json文件
	{
		std::wstring szRcPathOut;
		RelativePath2FullPath(wFilePath, szRcPathOut);
		std::list<std::wstring> listFileName;
		CommonFunc::GetFolderFile(szRcPathOut, L"txt", listFileName);
		for (const auto& it : listFileName)
		{
			if (!ReadJsonFile<_TOutputHandle, CONT>(wFilePath + it + L".txt", cont))
			{
				return false;
			}
		}
		return true;
	}
	template <typename _TOutputHandle, typename CONT>
	static bool ReadJsonFile(const std::wstring& wFilePath, CONT* cont)		// 读Json的通用接口
	{
		std::wstring szRcPathOut;
		CommonFunc::RelativePath2FullPath(wFilePath, szRcPathOut);
		std::wstring wstrFile = CommonFunc::ReadInputFile(szRcPathOut);
		
		SubJsonAnnotation(wstrFile);	// 去掉 #注释
		_TOutputHandle MyOutputHandler(cont);
		BaseOutputHandler<_TOutputHandle> handler(MyOutputHandler);
		rapidjson::GenericReader<rapidjson::UTF16<>, rapidjson::UTF16<> > reader;
		rapidjson::GenericStringStream<rapidjson::UTF16<> > ss(wstrFile.c_str());
		if (!reader.Parse(ss, handler))
		{
			std::wstring wstrTemp = CommonFunc::StringToWString(GetParseError_En(reader.GetParseErrorCode()));
			CString strError;
			strError.Format(L"Error(%u): %s From %s", (unsigned)reader.GetErrorOffset(), wstrTemp.c_str(), wFilePath.c_str());
			ErrorMessageBox(strError);
			return false;
		}
		wprintf_s(L"Read File From '%s' Success!\n", szRcPathOut.c_str());
		return true;
	}

private:
	static void SubJsonAnnotation(std::wstring& wstrInOut);	// 去掉#注释
};

class CMathFunc
{
public:
	static long long XYTran2Index(long long x, long long y, long long width, long long height);
	static void IndexTran2XY(int* x, int* y, int index, int width, int height);
	static D3DXVECTOR2 Vec2Rotate(const D3DXVECTOR2& vec2, double ang);	// 逆时针旋转ang
	
	template <typename T>
	static bool IsBetween(const T& x, const T& min, const T& max)	// 是否在[min, max]区间内
	{
		return (min <= x && x <= max);
	}
	template <typename T>
	static T Saturate(const T& x, const T& min, const T& max)	// 钳制到[min, max]
	{
		if (x < min)
		{
			return min;
		}
		else if (x > max)
		{
			return max;
		}
		return x;
	}
	template <typename T>
	static T Lerp(const T& In1, const T& In2, float s)
	{
		return (In2 - In1) * s + In1;
	}
};